﻿using MvcFileUploader.Models;
using SAIM.Models;
using SAIM.Models.BLL;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace SAIM.Controllers
{
    [Authorize]
    public class EVirtualController : Controller
    {
        private SAIMIdentity UserIdentity
        {
            get { return new SAIMIdentity(User.Identity); }
        }

        public enum EVirtualMessage
        {
            ListCreatedSuccessfully,
            ListEditedSuccessfully,
            ListDeletedSuccessfully,
            ColumnAddedSuccessfully,
            ColumnEditedSuccessfully,
            ColumnDeletedSuccessfully,
            RowAddedSuccessfully,
            RowEditedSuccessfully,
            RowDeletedSuccessfully,
            AddColumnError,
            EditColumnError,
            DeleteColumnError,
            AddRowError,
            EditRowError,
            DeleteRowError,
            AddListError,
            FileUploadError
        }

        [HttpGet]
        public ActionResult Lists(EVirtualMessage? message, string item, EVirtualMessage? errorMessage, string validationErrors)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");

            using(ListsBLL lists = new ListsBLL())
            {
                ViewBag.ItemSelected = (item != null) ? item.Replace(" ", string.Empty) : null;
                ViewBag.StatusMessage = GetStatusMessage(message);
                ViewBag.ErrorMessage = GetStatusMessage(errorMessage);
                ViewBag.ValidationErrors = validationErrors;
                return View(new ListsViewModel(lists.GetLists(UserIdentity.GetUserId())));
            }
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Lists(ListsViewModel model)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Create Lists");

            using (ListsBLL lists = new ListsBLL())
            {
                if (ModelState.IsValid)
                {
                    // Creamos la nueva lista
                    if (lists.AddList(model.Id, UserIdentity.GetUserId()))
                    {
                        ViewBag.StatusMessage = GetStatusMessage(EVirtualMessage.ListCreatedSuccessfully);
                        ViewBag.ErrorMessage = string.Empty;
                    }
                    else
                    {
                        ViewBag.StatusMessage = string.Empty;
                        ViewBag.ErrorMessage = GetStatusMessage(EVirtualMessage.AddListError);
                    }
                    
                }
                return View(new ListsViewModel(lists.GetLists(UserIdentity.GetUserId())));
            }
        }

        [HttpPost]
        public ActionResult _GetList(string name)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");

            using(ListsBLL lists = new ListsBLL())
            {
                // Obtenemos el modelo a utilizar mediante el nombre de la lista
                ListsViewModel model = lists.GetList(name, UserIdentity.GetUserId());
                if (model != null)
                    return PartialView(model);
                else throw new HttpException(403, "Access Denied");
            }
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult EditList(ListsViewModel model)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            string statusMessage = string.Empty;

            if (ModelState.IsValid)
            {
                using (ListsBLL lists = new ListsBLL())
                {
                    // Si la variable Delete es activa se elimina la lista
                    if (model.Delete)
                    {
                        // Primero eliminamos todos los archivos adjuntos en esta lista
                        if(lists.RemoveListAttachments(model.Id))
                        {
                            // Si todo va bien eliminamos la lista
                            using(ListsBLL itemToDelete = new ListsBLL())
                            {
                                itemToDelete.RemoveList(model.Id);
                            }
                        }
                        statusMessage = "ListDeletedSuccessfully";
                    }
                    else // Agregar, Editar o eliminar usuarios en la lista
                    {
                        foreach(UsersLists user in model.Users)
                        {
                            if (!user.Delete) // Actualizamos los datos de usuario
                                lists.AddUpdateUser(model.Id, user);
                            else // Eliminamos el usuario en caso de haber sido indicado
                                lists.RemoveUser(model.Id, user.UserUPN);
                        }
                        statusMessage = "ListEditedSuccessfully";
                    }
                }
            }
            return RedirectToAction("Lists", new { message=statusMessage, item=model.Id });
        }

        [HttpGet]
        public ActionResult _AddColumn(string listId)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            return PartialView(new ColumnData() { ListId = listId });
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult _AddColumn(ColumnData model)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            string statusMessage = string.Empty;
            string errorMessage = string.Empty;

            if (ModelState.IsValid)
            {
                using (ListStructureBLL column = new ListStructureBLL())
                {
                    // Creamos la nueva columna
                    if(column.InsertColumn(model))
                    {
                        statusMessage = "ColumnAddedSuccessfully";
                    }
                    else
                    {
                        errorMessage = "AddColumnError";
                    }
                }
            }
            else
            {
                errorMessage = "AddColumnError";
            }
            return RedirectToAction("Lists", new { message = statusMessage, item = model.ListId, errorMessage = errorMessage });
        }

        [HttpPost]
        public ActionResult _GetDataOptions(string dataType)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            return PartialView(new ColumnData() { DataType = dataType });
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult EditColumn(ColumnData model)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            string statusMessage = string.Empty;
            string errorMessage = string.Empty;

            using (ListsBLL lists = new ListsBLL())
            {
                // Obtenemos el modelo mediante el nombre de la lista
                if (lists.GetList(model.ListId, UserIdentity.GetUserId()) != null)
                {
                    if(model.DeleteColumn)
                    {
                        using (ListStructureBLL columnBLL = new ListStructureBLL())
                        {
                            // Eliminamos la columna
                            if (columnBLL.RemoveColumn(model.ListId, model.ColumnName))
                                statusMessage = "ColumnDeletedSuccessfully";
                            else
                                errorMessage = "DeleteColumnError";
                        }
                    }
                    return RedirectToAction("Lists", new { message = statusMessage, item = model.ListId, errorMessage = errorMessage });
                }
                else throw new HttpException(403, "Access Denied");
            }
            
        }

        [HttpGet]
        public ActionResult _AddItem(string listId)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            using(ListsBLL list = new ListsBLL())
            {
                return PartialView(new AddItemViewModel(listId, list.GetListStructure(listId)));
            }
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult _AddItem(Dictionary<string, string> model)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            string listId = model.FirstOrDefault(m => m.Key == "ListId").Value;
            string validationErrors;

            if(listId != null)
                using (ListsBLL lists = new ListsBLL())
                {
                    // Obtenemos el modelo mediante el nombre de la lista
                    ListsViewModel list = lists.GetList(listId, UserIdentity.GetUserId());
                    if (list != null)
                    {
                        using (ListStructureBLL ls = new ListStructureBLL())
                        {
                            // Validamos que los datos a insertar sean correctos
                            validationErrors = ls.ValidateDictionary(model);
                            if((validationErrors == null) || (validationErrors == string.Empty))
                            {
                                //Insertamos la nueva tupla (Renglón)
                                if(ls.InsertRow(model))
                                    return RedirectToAction("Lists", new { message = "RowAddedSuccessfully", item = listId});
                                else
                                    return RedirectToAction("Lists", new { message = string.Empty, item = listId, errorMessage = "AddRowError"});
                            }
                        }
                    }
                    else throw new HttpException(403, "Access Denied");
                }
            else throw new HttpException(403, "Access Denied");

            return RedirectToAction("Lists", new { message = string.Empty, item = listId, errorMessage = string.Empty, validationErrors = validationErrors });
        }

        [HttpGet]
        public ActionResult _EditItem(string listId, string columnId)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");

            using (ListsBLL list = new ListsBLL())
            {
                return PartialView(new EditItemViewModel(listId, list.GetListStructure(listId), list.GetRow(listId, columnId)));
            }
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult _EditItem(Dictionary<string, string> model)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            string listId = model.FirstOrDefault(m => m.Key == "ListId").Value;
            string deleteRow = model.FirstOrDefault(m => m.Key == "DeleteRow").Value;
            string validationErrors;

            if (listId != null)
                using (ListsBLL lists = new ListsBLL())
                {
                    // Carga del modelo mediante el nombre de la lista
                    ListsViewModel list = lists.GetList(listId, UserIdentity.GetUserId());
                    if (list != null)
                    {
                        using (ListStructureBLL ls = new ListStructureBLL())
                        {
                            if (deleteRow == "True") // Eliminamos la tupla
                            {
                                if (ls.DeleteRow(model)) 
                                    return RedirectToAction("Lists", new { message = "RowDeletedSuccessfully", item = listId });
                                else
                                    return RedirectToAction("Lists", new { message = string.Empty, item = listId, errorMessage = "DeleteRowError" });
                            }
                            else // Editamos la información de la tupla
                            {
                                // Validamos que los datos a modificar sean correctos
                                validationErrors = ls.ValidateDictionary(model);
                                if ((validationErrors == null) || (validationErrors == string.Empty))
                                {
                                    if (ls.EditRow(model))
                                        return RedirectToAction("Lists", new { message = "RowEditedSuccessfully", item = listId });
                                    else
                                        return RedirectToAction("Lists", new { message = string.Empty, item = listId, errorMessage = "EditRowError" });
                                }
                            }
                        }
                    }
                    else throw new HttpException(403, "Access Denied");
                }
            else throw new HttpException(403, "Access Denied");

            return RedirectToAction("Lists", new { message = string.Empty, item = listId, errorMessage = string.Empty, validationErrors = validationErrors });
        }

        [HttpPost]
        public ActionResult GetListData(string listId, int current, int rowCount, Dictionary<object, string> sort, string searchPhrase)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            int _current = current;
            int _rowCount = rowCount;

            using (ListsBLL lists = new ListsBLL())
            {
                // Obtenemos las tuplas de la lista y las devolvemos mediante un objeto JSON
                return new JsonResult()
                {
                    Data = new GetListDataViewModel(lists.GetData(listId, sort, searchPhrase), current, rowCount)
                };
            }
        }

        [HttpGet]
        public ActionResult _UploadFile(string listId, string columnId)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");

            using (ListsBLL list = new ListsBLL())
            {
                // Obtenemos el modelo a utilizar mediante el nombre de la lista
                ListsViewModel model = list.GetList(listId, UserIdentity.GetUserId());
                if (model != null)
                {
                    ViewBag.ListId = model.Id;
                    ViewBag.ColumnId = columnId;
                    return PartialView();
                }
                else throw new HttpException(403, "Access Denied");
            }
        }

        [HttpPost]
        public ActionResult UploadFile(string listId, string columnId)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            var statuses = new List<ViewDataUploadFileResult>();
            string pathForSaving = Server.MapPath("~/Content/uploads/" + UserIdentity.GetUserId()); // Ruta en la cual se guardara el archivo

            using (ListsBLL list = new ListsBLL())
            {
                // Obtenemos el modelo mediante el nombre de la lista
                ListsViewModel model = list.GetList(listId, UserIdentity.GetUserId());
                if (model != null)
                {
                    // Si no existe el directorio del usuario, se crea
                    if (!CreateFolderIfNeeded(pathForSaving))
                        throw new HttpException(404, "Can not create file");
                    // Se iteran todos los archivos a adjuntar
                    for (var i = 0; i < Request.Files.Count; i++)
                    {
                        using (AttachmentsBLL attachment = new AttachmentsBLL())
                        {
                            var myFile = Request.Files[i]; // Archivo a adjuntar
                            // Adjuntamos el archivo
                            var st = attachment.AttachListFile(myFile, UserIdentity.GetUserId(), listId, long.Parse(columnId), pathForSaving);
                            statuses.Add(st);
                            // Si el archivo no pudo ser adjuntado se redirige a la vista principal /EVirutal/Lists
                            if(st.error != null && st.error != string.Empty)
                                return RedirectToAction("Lists", new { item = listId });
                        }
                    }
                    var viewresult = new JsonResult() { Data = new { files = statuses } };

                    return viewresult;
                }
                else throw new HttpException(403, "Access Denied");
            }
        }

        [HttpPost]
        public ActionResult GetListAttachments(string listId, string columnId, int current, int rowCount, Dictionary<object, string> sort, string searchPhrase)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            int _current = current;
            int _rowCount = rowCount;

            using (AttachmentsBLL attachments = new AttachmentsBLL())
            {
                // Devolvemos todos los archivos adjuntos mediante un objeto JSON
                return new JsonResult()
                {
                    Data = attachments.GetListAttachements(listId, long.Parse(columnId), UserIdentity.GetUserId(), current, rowCount, searchPhrase)
                };
            }
        }

        [HttpGet]
        public ActionResult GetAttachedFile(string listId, string attachmentId)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            string filePath, fileName;

            filePath = fileName = string.Empty;
            using (ListsBLL list = new ListsBLL())
            {
                // Validamos que el usuario tenga acceso a la lista
                if(list.GetList(listId, UserIdentity.GetUserId()) == null)
                    throw new HttpException(404, "Page Not Found");
                using (AttachmentsBLL attachment = new AttachmentsBLL())
                {
                    // Obtenemos la ruta del archivo y el nombre real del arhivo a descargar
                    attachment.GetAttachmentName(listId, attachmentId, ref filePath, ref fileName);
                    // Si el archivo no existe devolvemos una excepcion
                    if (fileName == null)
                        throw new HttpException(404, "Item Not Found");
                    // Si el archivo existe lo devolvemos
                    return File(Path.Combine(filePath, attachmentId), "multipart/form-data", fileName);
                }
            }
        }

        [HttpPost]
        public ActionResult _GetFileEditions(string listId, string columnId, string fileName)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");

            using (ListsBLL list = new ListsBLL())
            {
                // Validamos que el usuario tenga acceso a la lista
                if (list.GetList(listId, UserIdentity.GetUserId()) == null)
                    throw new HttpException(404, "Page Not Found");

                using (AttachmentsBLL attachment = new AttachmentsBLL())
                {
                    ViewBag.ListId = listId;
                    // Obtenemos el modelo a utilizar 
                    GetFileEditionsViewModel model = new GetFileEditionsViewModel(attachment.GetAttachmentEditions(listId, long.Parse(columnId), fileName));
                    return PartialView(model);
                }
            }
        }

        [HttpPost]
        public ActionResult RemoveFile(string listId, string columnId, string mask)
        {
            // Validacion de permisos necesarios para acceder a las listas personalizadas
            // Si no se cuenta con los permisos requeridos se lanza una excepcion
            UserIdentity.ValidatePermissions("Lists");
            string filePath, fileName;

            filePath = fileName = string.Empty;
            using (ListsBLL list = new ListsBLL())
            {
                // Validamos que el usuario tenga acceso a la lista
                if (list.GetList(listId, UserIdentity.GetUserId()) == null)
                    throw new HttpException(403, "Access denied");
                using (AttachmentsBLL attachment = new AttachmentsBLL())
                {
                    // Eliminamos el archivo y devolvemos el estaus mediante un objeto JSON ({ status: true|false })
                    return new JsonResult()
                    {
                        Data = new { status = attachment.RemoveFile(listId, long.Parse(columnId), mask) }
                    };
                }
            }
        }

        #region Métodos Auxiliares

        /// <summary>
        /// Devuelve una cadena de estatus de acuerdo al enumerador recibido  
        /// </summary>
        /// <param name="message">Enumerador que indica la cadena a devolver</param>
        /// <returns></returns>
        private string GetStatusMessage(EVirtualMessage? message)
        {
            string statusMessage =
                        message == EVirtualMessage.ListCreatedSuccessfully ? "Lista creada exitosamente" :
                        message == EVirtualMessage.ListDeletedSuccessfully ? "Lista eliminada exitosamente" :
                        message == EVirtualMessage.ListEditedSuccessfully ? "Lista editada exitosamente" :
                        message == EVirtualMessage.ColumnAddedSuccessfully ? "Columna agregada exitosamente" :
                        message == EVirtualMessage.ColumnEditedSuccessfully ? "Columna editada exitosamente" :
                        message == EVirtualMessage.ColumnDeletedSuccessfully ? "Columna eliminada exitosamente" :
                        message == EVirtualMessage.RowAddedSuccessfully ? "Registro agregado exitosamente" :
                        message == EVirtualMessage.RowEditedSuccessfully ? "Registro editado exitosamente" :
                        message == EVirtualMessage.RowDeletedSuccessfully ? "Registro eliminado exitosamente" :
                        message == EVirtualMessage.AddColumnError ? "No se puede agregar la columna" :
                        message == EVirtualMessage.EditColumnError ? "No se puede editar la columna" :
                        message == EVirtualMessage.DeleteColumnError ? "No se puede eliminar la columna" :
                        message == EVirtualMessage.AddRowError ? "No se puede agregar el registro" :
                        message == EVirtualMessage.EditRowError ? "No se puede editar el registro" :
                        message == EVirtualMessage.DeleteRowError ? "No se puede eliminar el registro" :
                        message == EVirtualMessage.AddListError ? "No se puede agregar la lista" :
                        message == EVirtualMessage.FileUploadError ? "Archivo no adjuntado. Intente nuevamente" : "";

            return statusMessage;
        }

        /// <summary>
        /// En caso de no existir, crea los directorios indicados por la ruta.
        /// </summary>
        /// <param name="path">La ruta a crear</param>
        /// <returns></returns>
        private bool CreateFolderIfNeeded(string path)
        {
            bool result = true;
            if (!Directory.Exists(path))
            {
                try
                {
                    Directory.CreateDirectory(path);
                }
                catch (Exception)
                {
                    result = false;
                }
            }
            return result;
        }

        #endregion
    }
}